<?php
class ORM {
  private $my_pdo;
  private $db_host;
  private $db_name;
  private $db_login;
  private $db_pass;
  private $db_charset;
  
  public function __construct($db_host=DB_HOST, $db_name=DB_NAME, $db_login=DB_LOGIN, $db_pass=DB_PASS, $db_charset=DB_CHARSET) {
    $this->db_host = $db_host;
    $this->db_name = $db_name;
    $this->db_login = $db_login;
    $this->db_pass = $db_pass;
    $this->db_charset = $db_charset;
  }
  
  public function __connect() {
    if (!$this->my_pdo) {
      $this->my_pdo = new PDO("mysql:host=$this->db_host;dbname=$this->db_name;charset=$this->db_charset", $this->db_login, $this->db_pass);
      if (!defined ('DEBUG_ENABLED') || DEBUG_ENABLED) {
        $this->my_pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      }
    }
  }
  
  public function exec($sql) {
    $this->__connect();
    $stmt = $this->my_pdo->prepare($sql);
    $stmt->execute();
  }
  
  public function last_id() {
    $this->__connect();
    return $this->my_pdo->lastInsertId();
  }
  
  public function close() {
    return $this->my_pdo = null;
  }
  
  public function begin() {
    $this->__connect();
    return $this->my_pdo->beginTransaction();
  }
  
  public function commit() {
    $this->__connect();
    return $this->my_pdo->commit();
  }
  
  public function get($table, $order, $queue, $page, $size, $opts) {
    $this->__connect();
    $sql = 'SELECT ' . (($opts != NULL && isset($opts->sel)) ? $opts->sel : '*') . " FROM `$table` AS `t`";
    $stmt = $this->__execute($sql, $order, $queue, $page, $size, $opts);
    
    $result = new stdClass();
    $result->d = array();
    $result->o = $order;
    $result->q = $queue;
    $result->p = $page;
    $result->s = $size;
    
    $i = 0;
    while ($i < $stmt->rowCount()) {
      $result->d[] = $stmt->fetch(PDO::FETCH_OBJ);
      $i++;
    }
    
    if ($page && $size) {
      $sql = "SELECT COUNT(t.id) AS total FROM `$table` AS `t`";
      $stmt = $this->__execute($sql, NULL, NULL, NULL, NULL, $opts);
      $stmt->execute();
      $result->t = $stmt->fetch(PDO::FETCH_OBJ)->total;
    } else {
      $result->t = $stmt->rowCount();
    }
    return $result;
  }
  
  public function add($table, $obj) {
    $this->__connect();
    $sql = "INSERT INTO `$table` (`id`";
    $sql2 = "(NULL";
    $args = array();
    foreach ($obj as $key => $value) {
      if(!$this->__is_valid($key, $value)) {
        continue;
      }
      $sql .= ", `$key`";
      $sql2 .= ", ?";
      $args[] = $value;
    }
    $sql .= ") VALUE $sql2)";
    $stmt = $this->my_pdo->prepare($sql);
    $stmt->execute($args);
  }
  
  public function update($table, $obj) {
    $this->__connect();
    $sql = "UPDATE `$table` SET ";
    $args = array();
    foreach ($obj as $key => $value) {
      if(!$this->__is_valid($key, $value)) {
        continue;
      }
      $sql .= "`$key` = ?, ";
      $args[] = $value;
    }
    $sql = substr($sql, 0, strlen($sql) - 2);
    $sql .= " WHERE `id` = '$obj->id'";
    $stmt = $this->my_pdo->prepare($sql);
    $stmt->execute($args);
  }
  
  public function delete($table, $obj) {
    $this->__connect();
    $opts = new stdClass();
    $opts->cd = "`id` = :v1";
    $opts->cdv = array(':v1' => $obj->id);
    $sql = "DELETE FROM `$table`";
    $this->__execute($sql, NULL, NULL, NULL, NULL, $opts);
  }
  
  public function delete_by_opts($table, $opts) {
    $this->__connect();
    $sql = "DELETE FROM `$table`";
    $this->__execute($sql, NULL, NULL, NULL, NULL, $opts);
  }
  
  public function __execute($init_sql, $order, $queue, $page, $size, $opts) {
    $sql = $init_sql;
    $sql .= (($opts != NULL && isset($opts->jt)) ? $opts->jt : '');
    $sql .= (($opts != NULL && isset($opts->cd) && !empty($opts->cd)) ? " WHERE $opts->cd " : '');
    $sql .= (($opts && isset($opts->gb)) ? " GROUP BY $opts->gb "  : ' ');
    $sql .= (($order && $queue) ? "ORDER BY $order $queue " : '') . (($page && $size) ? 'LIMIT :from, :limit' : '');
    $stmt = $this->my_pdo->prepare($sql);
    if ($opts != NULL && isset($opts->cdv)) {
      foreach ($opts->cdv as $key => &$value) {
        $stmt->bindParam($key, $value);
      }
    }
    if ($page && $size) {
      $from = ($page - 1) * $size;
      $stmt->bindParam(':from', $from, PDO::PARAM_INT);
      $stmt->bindParam(':limit', $size, PDO::PARAM_INT);
    }
    $stmt->execute();
    return $stmt;
  }
  
  public function __is_valid($key, $value) {
    if (gettype($value) == 'array' ||
        gettype($value) == 'object' ||
        gettype($value) == 'resource' ||
        gettype($value) == 'NULL' ||
        gettype($value) == 'unknown type') {
      return false;
    }
    if ($key == 'id') {
      return false;
    }
    if (substr($key, 0, 2) == '__') {
      return false;
    }
    return true;
  }
}
?>